#include "serial.h"
#include "Com.h"
#include "queue.h"


#define SERIAL_RX_QUEUELENGTH   200


typedef enum {
    RX_STATE_INI = 0,
    RX_STATE_WAIT,
    RX_STATE_ID,
    RX_STATE_DATA,
    RX_STATE_CRC
}
Serial_Rx_State_t;


/*************** GLOBAL VARIABLES ************/
xQueueHandle Serial_Rx_CharQueue;
static uint32 Serial_Rx_IniFlag = 0;
//static uint32 Serial_TxFlag;

uint8 ch;
uint8 ch_old;
Serial_Rx_State_t state;

void Serial_Rx_Ini(void)
{
    Serial_Rx_CharQueue = xQueueCreate(SERIAL_RX_QUEUELENGTH, sizeof(uint8));

    state = RX_STATE_INI;

    Serial_Rx_IniFlag = 1;
}

void Serial_Rx_MainFunction(void)
{
    if(Serial_Rx_IniFlag == 1)
    {
        static Com_Message_t msg;
        static uint8 crc_calc, cnt;

        while(xQueueReceive(Serial_Rx_CharQueue, &ch, 0 /*no blocking time*/))
        {
            switch(state)
            {
                case RX_STATE_INI:
                {
                    state = RX_STATE_WAIT;
                }
                break;

                case RX_STATE_WAIT:
                {
                    if((ch == (~ch_old)) && (ch <= COM_MSGLENGTH))
                    {
                        msg.len = ch_old;
                        state = RX_STATE_CRC;
                    }
                }
                break;

                case RX_STATE_ID:
                {
                    msg.id = ch;
                    crc_calc = ch;
                    cnt = 0;
                    state = RX_STATE_DATA;
                }
                break;

                case RX_STATE_DATA:
                {
                    crc_calc += ch;
                    msg.data[cnt] = ch;
                    cnt++;
                    if(cnt == msg.len)
                    {
                        state = RX_STATE_CRC;
                    }
                }
                break;

                case RX_STATE_CRC:
                {
                    if(crc_calc == ch)
                    {
                        (void)xQueueSend(Com_RxMessageQueue, &msg, 0 /*no block time*/);
                    }

                    state = RX_STATE_INI;
                }
                break;
            }

            ch_old = ch;
        }
    }
}

void Serial_Rx_IntHandler(void)
{
    static uint8 ch;

    /* Are any Rx interrupts pending? */
    if(IFS1bits.U2RXIF == 1)
    {
        while(U2STAbits.URXDA)
        {
            /* Retrieve the received character and place it in the queue of
            received characters. */
            ch = U2RXREG;
            xQueueSendFromISR(Serial_Rx_CharQueue, &ch, (signed portBASE_TYPE *)0);
        }
        IFS1CLR = _IFS1_U2RXIF_MASK;
    }
}

